/**
 * 
 */
package webreg.model;
import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;

import webreg.model.exceptions.EmptyDescriptionException;
import webreg.model.exceptions.NegativNumberException;

/** Class which wraps age classifications for athletics
 * 
 * @author STKNOLL
 */
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
@XmlAccessorType(XmlAccessType.NONE)
public class AgeClassification implements Cloneable {
	
	@XmlAttribute(name = "label")
	private String mLabel;
	@XmlAttribute(name = "startAge")
	private int mAgeStart;
	@XmlAttribute(name = "endAge")
	private int mAgeEnd;
	@XmlAttribute (name = "sex")
	private Sex mSex;	
	
	/** Constructor or age classification
	 */
	public AgeClassification() {
		mLabel = "";
		mAgeStart = 0;
		mAgeEnd = 0;
		mSex = Sex.MALE;
	}

	/** Constructor for age classification with parameters
	 * 
	 * Generate a AgeClassification.  with the following parameters.
	 * 
	 * @param label The Name of the entry
	 * @param ageStart The start value of a entry range 
	 * @param ageEnd The end value of a entry range
	 * @param sex The sex for which this classification is valid
	 * @throws EmptyDescriptionException 
	 * @throws NegativNumberException 
	 */
	public AgeClassification(String label, int ageStart, int ageEnd, Sex sex) throws EmptyDescriptionException, NegativNumberException {
		this();
		setLabel(label);		
		setSex(sex);
		setAgeBoundaries(ageStart, ageEnd);
	}

	/** Copy constructor
	 * 
	 * @param toCopy The age classification to copy
	 * @throws EmptyDescriptionException 
	 * @throws NegativNumberException 
	 */
	public AgeClassification(AgeClassification toCopy) {
		this( );
		mLabel = toCopy.mLabel;
		mAgeStart = toCopy.mAgeStart;
		mAgeEnd = toCopy.mAgeEnd;
		mSex = toCopy.mSex;
	}
	
	
	/** Implementation of the equals function
	 * 
	 * Compares a ages classification with the given one
	 * 
	 * @param toCompare The age classification used for compare
	 * 
	 */
	public boolean equals(AgeClassification toCompare) {
		if (this.mAgeEnd != toCompare.mAgeEnd) return false;
		if (this.mAgeStart != toCompare.mAgeStart) return false;
		if (this.mLabel.equals(toCompare.mLabel) == false ) return false;
		if (this.mSex.equals(toCompare.mSex) == false) return false;
		return true;
	}
	
	/** Return the age range end of the classification
	 * 
	 * @return The age range end
	 */
	public int getAgeEnd() {
		return mAgeEnd;
	}

	/** Set the age range end of the classification
	 * 
	 * @param newAgeEnd The range end of the classification
	 * @throws NegativNumberException 
	 */
	public void setAgeEnd(int newAgeEnd) throws NegativNumberException {
		if (newAgeEnd < 0 ) throw new NegativNumberException( newAgeEnd, "AgeClassification, endAge" + getLabel() );
		mAgeEnd = newAgeEnd;
	}

	/** Return the age range start of the classification
	 * 
	 * @return The age range start value
	 */
	public int getAgeStart() {
		return mAgeStart;
	}

	/** Set the age range start of the classification
	 * 
	 * @param newAgeStart The age range start value to set
	 * @throws NegativNumberException 
	 */
	public void setAgeStart(int newAgeStart) throws NegativNumberException {
		if (newAgeStart < 0 ) throw new NegativNumberException( newAgeStart, "AgeClassification, startAge " + getLabel() );
		mAgeStart = newAgeStart;
	}

	public void setAgeBoundaries(int inAgeStart, int inAgeEnd) throws NegativNumberException {
		setAgeStart(inAgeStart);
		setAgeEnd(inAgeEnd);
		swapIfNeeded();
	}
	
	/** Returns the age classification label
	 * 
	 * @return The label as string
	 */
	public String getLabel() {
		return mLabel;
	}

	/** Sets the label of the age classification
	 * 
	 * @param label The label to set for the classification
	 * @throws EmptyDescriptionException 
	 */
	public void setLabel(String label) throws EmptyDescriptionException {
		if ((label == null) || (label.trim().equals("") )) {
			throw new EmptyDescriptionException("AgeClassification " + getLabel());
		}
		mLabel = label;
	}	

	/** Returns the sex for which this classification is valid
	 * 
	 * @return The sex of this classification
	 */
	public Sex getSex() {
		return mSex;
	}

	/** Set the sex of this classification
	 * 
	 * @param sex The sex to set
	 */
	public void setSex(Sex sex) {
		this.mSex = sex;
	}

	/** Will lookup a given age if it fits in the range of the entry
	 * 
	 * @param age The age to test matching for
	 * @return True if age is in the range of the entry
	 */
	public boolean matchAge(int age) {
		if ( (getAgeStart() <= age) && ( age <= getAgeEnd()) ) return true;
		else return false;
	}

	@Override
	public String toString() {
		return getLabel() + ", " + getSex().getValue() + ", " + getAgeStart() + ", " + getAgeEnd();
	}
	
	@Override
	public Object clone() {
		AgeClassification newClass = new AgeClassification();
		newClass.mLabel = mLabel;
		newClass.mAgeStart = mAgeStart;
		newClass.mAgeEnd = mAgeEnd;
		newClass.mSex = mSex;
		return newClass;
	}	
	
	/** Compare an age classification against another one
	 * 
	 * @param other The age classification to compare this one against
	 * @return <0 if this one is smaller, 0 if even, of >0 if the other other one is smaller
	 */
	public int compareTo(AgeClassification other) {
		if (mAgeEnd < other.mAgeEnd) {return -1; }
		else if(mAgeEnd > other.mAgeEnd) {return 1; }
		
		if (mAgeStart < other.mAgeStart) {return -1; }
		else if(mAgeStart > other.mAgeStart) {return 1; }
		
		int labelCompare = mLabel.compareTo(other.mLabel);
		if (labelCompare != 0) { return labelCompare; }
		
		int sexCompare = mSex.compareTo(other.mSex);
		if (sexCompare != 0) { return sexCompare; }
		
		return 0;
	}
	
	/** Swap the start and end age if need.
	 * 
	 * Swap the start and end age if the start age is bigger than the end age.
	 */
	private void swapIfNeeded() {
		if (mAgeEnd < mAgeStart) {
			int tmp = mAgeEnd;
			mAgeEnd = mAgeStart;
			mAgeStart = tmp;
		}		
	}
}
